home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume7 / read-vms-backs < prev    next >
Encoding:
Internet Message Format  |  1987-01-19  |  32.2 KB

  1. Subject:  v07i099:  Read VMS backup tapes
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: seismo!enea!luthcad!sow (Sven-Ove Westberg)
  6. Mod.sources: Volume 7, Issue 99
  7. Archive-name: read-vms-backs
  8.  
  9. This program reads a VMS backup tape, it can use the rmtlib for remote tape
  10. access.
  11.     Sven-Ove Westberg
  12.  
  13. [  I do not have any VMS backup tapes with which to test this.  --r$  ]
  14.  
  15. #! /bin/sh
  16. # This is a shell archive, meaning:
  17. # 1. Remove everything above the #! /bin/sh line.
  18. # 2. Save the resulting text in a file.
  19. # 3. Execute the file with /bin/sh (not csh) to create:
  20. #    README
  21. #    vmsbackup.1
  22. #    Makefile
  23. #    vmsbackup.c
  24. #    match.c
  25. # This archive created: Sun Dec  7 19:56:28 1986
  26. echo shar: "extracting 'README'" '(575 characters)'
  27. if test -f 'README'
  28. then
  29.     echo shar: "will not over-write existing file 'README'"
  30. else
  31. sed 's/^    X//' << \SHAR_EOF > 'README'
  32.     XThis progam reads a VMS backuptape.
  33.     X
  34.     XThe tape program is orginally written by John Douglas Carey and
  35.     Xthe pattern matching routine by some unknown on the net. 
  36.     X
  37.     XThe remote tape option use the rmtlib from mod.sources.
  38.     X
  39.     XA good way to archive remotetape access for users with only
  40.     Xa local account is to create a "netwide" user tar and let
  41.     Xthe remote tape programs do suid to user tar.
  42.     X
  43.     XThe program is tested on vax and sun.
  44.     X
  45.     X
  46.     XSven-Ove Westberg 
  47.     XLulea University of Technology
  48.     XS-951 87  Lulea,  Sweden
  49.     XUUCP:  sow@luthcad.UUCP
  50.     XUUCP:  {decvax,philabs,seismo}!mcvax!enea!luthcad!sow
  51. SHAR_EOF
  52. if test 575 -ne "`wc -c < 'README'`"
  53. then
  54.     echo shar: "error transmitting 'README'" '(should have been 575 characters)'
  55. fi
  56. fi
  57. echo shar: "extracting 'vmsbackup.1'" '(3444 characters)'
  58. if test -f 'vmsbackup.1'
  59. then
  60.     echo shar: "will not over-write existing file 'vmsbackup.1'"
  61. else
  62. sed 's/^    X//' << \SHAR_EOF > 'vmsbackup.1'
  63.     X.TH VMSBACKUP 1 
  64.     X.SH NAME
  65.     Xvmsbackup \- read a VMS backup tape
  66.     X.SH SYNOPSIS
  67.     X.B vmsbackup
  68.     X.B \-{tx}[cdevw][s setnumber][f tapefile] 
  69.     X[ name ... ]
  70.     X.SH DESCRIPTION
  71.     X.I vmsbackup 
  72.     Xreads a VMS generated backup tape, converting the files
  73.     Xto Unix format and writing the files to disc.
  74.     XThe default operation of the program is to go through an entire
  75.     Xtape, extracting every file and writing it to disc.
  76.     XThis may be modified by the following options.
  77.     X.TP 8
  78.     X.B c
  79.     XUse complete filenames, including the version number.
  80.     XA colon and the octal version number will be appended to all filenames.
  81.     XA colon, rather than a semicolon, is used since the Unix Shell
  82.     Xuses the semicolon as the line separator.
  83.     XUsing a colon prevents the user from having to escape the semicolon
  84.     Xwhen referencing the filename.
  85.     XThis option is useful only when multiple versions of the same file
  86.     Xare on a single tape or when a file of the same name already
  87.     Xexists in the destination directory.
  88.     XThe default is to ignore version numbers.
  89.     X.TP 8
  90.     X.B d
  91.     Xuse the directory structure from VMS, the default value is off.
  92.     X.TP 8
  93.     X.B e
  94.     XProcess all filename extensions.
  95.     XSince this program is mainly intended to move source code and possibly
  96.     Xdata from a DEC system to a Unix system, the default is to ignore
  97.     Xall files whose filename extension specifies system dependent data.
  98.     XThe file types which will be ignored, unless the
  99.     X.B e
  100.     Xoption is specified, are
  101.     X.IP "" 10
  102.     Xexe     VMS executable file
  103.     X.br
  104.     Xlib     VMS object library file
  105.     X.br
  106.     Xobj     RSX object file
  107.     X.br
  108.     Xodl     RSX overlay description file
  109.     X.br
  110.     Xolb     RSX object library file
  111.     X.br
  112.     Xpmd     RSX post mortem dump file
  113.     X.br
  114.     Xstb     RSX task symbol table file
  115.     X.br
  116.     Xsys     RSX bootable system file
  117.     X.br
  118.     Xtsk     RSX executable task file
  119.     X.PP
  120.     X.TP 8
  121.     X.B f
  122.     XUse the next argument in the command line as the tape device to
  123.     Xbe used, rather than the default.
  124.     X.sp
  125.     XIf vmsbackup is compiled with the remote tape option
  126.     Xand the file name has the form
  127.     X.IR system [. user ]:/dev/???
  128.     X.I vmsbackup
  129.     Xwill use the tape drive /dev/??? on the remote system
  130.     X.IR system ,
  131.     Xvia
  132.     X.IR rsh (1),
  133.     Xand
  134.     X.IR rmt (8).
  135.     XThe optional
  136.     X.I user
  137.     Xportion of the pathname specifies the login name to use on the
  138.     Xremote system.
  139.     XIf it is not supplied, the current user's login name will be used.
  140.     XIn all the cases, the user must have the appropriate
  141.     Xpermissions on the remote machine, in order to use this facility.
  142.     XThe default is
  143.     X.I /dev/rmt8
  144.     X(drive 0, raw mode, 1600 bpi).
  145.     XThis must be a raw mode tape device.
  146.     X.TP 8
  147.     X.B s saveset
  148.     XProcess only the given saveset number.
  149.     X.TP 8
  150.     X.B t
  151.     XProduce a table of contents (a directory listing) on the standard output
  152.     Xof the files on tape.
  153.     X.TP 8
  154.     X.B v
  155.     XVerbose output.
  156.     XNormally
  157.     X.I vmsbackup 
  158.     Xdoes its work silently.
  159.     XThe verbose option will cause the filenames of the files being read from
  160.     Xtape to disk to be output on the standard output.
  161.     X.TP 8
  162.     X.B w
  163.     X.I vmsbackup
  164.     Xprints the action to be taken followed by file name, then
  165.     Xwait for user confirmation. If a word beginning with `y'
  166.     Xis given, the action is done. Any other input means don't do it.
  167.     X.TP 8
  168.     X.B x
  169.     Xextract the named files from the tape.
  170.     X.TP 8
  171.     XThe optional 
  172.     X.I name
  173.     Xargument specifies one or more filenames to be
  174.     Xsearched for specifically on the tape and only those files are to be processed.
  175.     XThe name may contain the usal sh(1) meta-characters *?![] \nnn.
  176.     X.SH FILES
  177.     X/dev/rmt\fIx\fP
  178.     X.SH SEE ALSO
  179.     Xrmtops(3)
  180.     X.SH BUGS
  181.     XThe filename match uses the complete VMS file names.
  182.     X
  183.     X.SH AUTHOR
  184.     XJohn Douglas Carey
  185.     X.br
  186.     XSven-Ove Westberg
  187. SHAR_EOF
  188. if test 3444 -ne "`wc -c < 'vmsbackup.1'`"
  189. then
  190.     echo shar: "error transmitting 'vmsbackup.1'" '(should have been 3444 characters)'
  191. fi
  192. fi
  193. echo shar: "extracting 'Makefile'" '(605 characters)'
  194. if test -f 'Makefile'
  195. then
  196.     echo shar: "will not over-write existing file 'Makefile'"
  197. else
  198. sed 's/^    X//' << \SHAR_EOF > 'Makefile'
  199.     X#
  200.     X#
  201.     XREMOTE=-DREMOTE            # -DREMOTE  use remote tape
  202.     XSWAP=                # -DSWAP swap bytes
  203.     XCFLAGS= $(SWAP) $(REMOTE)
  204.     XLFLAGS=
  205.     XLIBS= -lrmt               # remote magtape library
  206.     XOWNER=tar            # user for remote tape access
  207.     XMODE=4755
  208.     XBINDIR=/usr/local/bin
  209.     XMANSEC=l
  210.     XMANDIR=/usr/man/man$(MANSEC)
  211.     X
  212.     X#
  213.     Xvmsbackup: vmsbackup.o getopt.o match.o
  214.     X    cc $(LFLAGS) -o vmsbackup vmsbackup.o match.o getopt.o $(LIBS)
  215.     Xinstall:
  216.     X    install -m $(MODE) -o $(OWNER) -s vmsbackup $(BINDIR)    
  217.     X    cp vmsbackup.1 $(MANDIR)/vmsbackup.$(MANSEC)
  218.     Xclean:
  219.     X    rm -f vmsbackup *.o core
  220.     Xshar:
  221.     X    shar -a README vmsbackup.1 Makefile vmsbackup.c match.c \
  222.     X        > vmsbackup.shar
  223. SHAR_EOF
  224. if test 605 -ne "`wc -c < 'Makefile'`"
  225. then
  226.     echo shar: "error transmitting 'Makefile'" '(should have been 605 characters)'
  227. fi
  228. fi
  229. echo shar: "extracting 'vmsbackup.c'" '(16594 characters)'
  230. if test -f 'vmsbackup.c'
  231. then
  232.     echo shar: "will not over-write existing file 'vmsbackup.c'"
  233. else
  234. sed 's/^    X//' << \SHAR_EOF > 'vmsbackup.c'
  235.     X/*
  236.     X *
  237.     X *  Title:
  238.     X *    Backup
  239.     X *
  240.     X *  Decription:
  241.     X *    Program to read VMS backup tape
  242.     X *
  243.     X *  Author:
  244.     X *    John Douglas CAREY.
  245.     X *    Sven-Ove Westberg    (version 3.0)
  246.     X *
  247.     X *  Net-addess:
  248.     X *    john%monu1.oz@seismo.ARPA
  249.     X *    luthcad!sow@enea.UUCP
  250.     X *
  251.     X *  History:
  252.     X *    Version 1.0 - September 1984
  253.     X *        Can only read variable length records
  254.     X *    Version 1.1
  255.     X *        Cleaned up the program from the original hack
  256.     X *        Can now read stream files
  257.     X *    Version 1.2
  258.     X *        Now convert filename from VMS to UNIX
  259.     X *            and creates sub-directories
  260.     X *    Version 1.3
  261.     X *        Works on the Pyramid if SWAP is defined
  262.     X *    Version 1.4
  263.     X *        Reads files spanning multiple tape blocks
  264.     X *    Version 1.5
  265.     X *        Always reset reclen = 0 on file open
  266.     X *        Now output fixed length records
  267.     X *
  268.     X *      Version 2.0 - July 1985
  269.     X *        VMS Version 4.0 causes a rethink !!
  270.     X *        Now use mtio operations instead of opening and closing file
  271.     X *        Blocksize now grabed from the label
  272.     X *
  273.     X *    Version 2.1 - September 1985
  274.     X *        Handle variable length records of zero length.
  275.     X *
  276.     X *    Version 2.2 - July 1986
  277.     X *        Handle FORTRAN records of zero length.
  278.     X *        Inserted exit(0) at end of program.
  279.     X *        Distributed program in aus.sources
  280.     X *
  281.     X *    Version 2.3 - August 1986
  282.     X *        Handle FORTRAN records with record length fields
  283.     X *        at the end of a block
  284.     X *        Put debug output to a file.
  285.     X *        Distributed program in net.sources
  286.     X *
  287.     X *    Version 3.0 - December 1986
  288.     X *        Handle multiple saveset 
  289.     X *        Remote tape
  290.     X *        Interactive mode
  291.     X *        File name selection with meta-characters
  292.     X *        Convert ; to : in VMS filenames
  293.     X *        Flag for usage of VMS directory structure
  294.     X *        Flag for "useless" files  eg. *.exe
  295.     X *        Flag for use VMS version in file names
  296.     X *        Flag for verbose mode
  297.     X *        Flag to list the contents of the tape
  298.     X *        Distributed to mod.sources
  299.     X *
  300.     X *
  301.     X *  Installation:
  302.     X *
  303.     X *    Computer Centre
  304.     X *    Monash University
  305.     X *    Wellington Road
  306.     X *    Clayton
  307.     X *    Victoria    3168
  308.     X *    AUSTRALIA
  309.     X *
  310.     X */
  311.     X#include    <stdio.h>
  312.     X#include    <ctype.h>
  313.     X
  314.     X#include    <sys/ioctl.h>
  315.     X#include    <sys/types.h>
  316.     X#ifdef REMOTE
  317.     X#include    <local/rmt.h>
  318.     X#include    <sys/stat.h>
  319.     X#endif
  320.     X#include    <sys/mtio.h>
  321.     X#include    <sys/file.h>
  322.     X
  323.     X#ifdef pyr
  324.     X#define SWAP
  325.     X#endif pyr
  326.     X
  327.     X#ifdef sun
  328.     X#define SWAP
  329.     X#endif
  330.     X
  331.     Xstruct bbh {
  332.     X    short    bbh_dol_w_size;
  333.     X    short    bbh_dol_w_opsys;
  334.     X    short    bbh_dol_w_subsys;
  335.     X    short    bbh_dol_w_applic;
  336.     X    long    bbh_dol_l_number;
  337.     X    char    bbh_dol_t_spare_1[20];
  338.     X    short    bbh_dol_w_struclev;
  339.     X    short    bbh_dol_w_volnum;
  340.     X    long    bbh_dol_l_crc;
  341.     X    long    bbh_dol_l_blocksize;
  342.     X    long    bbh_dol_l_flags;
  343.     X    char    bbh_dol_t_ssname[32];
  344.     X    short    bbh_dol_w_fid[3];
  345.     X    short    bbh_dol_w_did[3];
  346.     X    char    bbh_dol_t_filename[128];
  347.     X    char    bbh_dol_b_rtype;
  348.     X    char    bbh_dol_b_rattrib;
  349.     X    short    bbh_dol_w_rsize;
  350.     X    char    bbh_dol_b_bktsize;
  351.     X    char    bbh_dol_b_vfcsize;
  352.     X    short    bbh_dol_w_maxrec;
  353.     X    long    bbh_dol_l_filesize;
  354.     X    char    bbh_dol_t_spare_2[22];
  355.     X    short    bbh_dol_w_checksum;
  356.     X} *block_header;
  357.     X
  358.     Xstruct brh {
  359.     X    short    brh_dol_w_rsize;
  360.     X    short    brh_dol_w_rtype;
  361.     X    long    brh_dol_l_flags;
  362.     X    long    brh_dol_l_address;
  363.     X    long    brh_dol_l_spare;
  364.     X} *record_header;
  365.     X
  366.     X/* define record types */
  367.     X
  368.     X#define    brh_dol_k_null    0
  369.     X#define    brh_dol_k_summary    1
  370.     X#define    brh_dol_k_volume    2
  371.     X#define    brh_dol_k_file    3
  372.     X#define    brh_dol_k_vbn    4
  373.     X#define brh_dol_k_physvol    5
  374.     X#define brh_dol_k_lbn    6
  375.     X#define    brh_dol_k_fid    7
  376.     X
  377.     Xstruct bsa {
  378.     X    short    bsa_dol_w_size;
  379.     X    short    bsa_dol_w_type;
  380.     X    char    bsa_dol_t_text[1];
  381.     X} *data_item;
  382.     X
  383.     X#ifdef    STREAM
  384.     Xchar    *def_tapefile = "/dev/rts8";
  385.     X#else
  386.     Xchar    *def_tapefile = "/dev/rmt8";
  387.     X#endif
  388.     Xchar    *tapefile;
  389.     X
  390.     Xchar    filename[128];
  391.     Xint    filesize;
  392.     X
  393.     Xchar    recfmt;        /* record format */
  394.     X
  395.     X#define            FAB_dol_C_UDF    0    /* undefined */
  396.     X#define            FAB_dol_C_FIX    1    /* fixed-length record */
  397.     X#define            FAB_dol_C_VAR    2    /* variable-length record */
  398.     X#define            FAB_dol_C_VFC    3    /* variable-length with fixed-length control record */
  399.     X#define         FAB_dol_C_STM    4    /* RMS-11 stream record (valid only for sequential org) */
  400.     X#define            FAB_dol_C_STMLF    5    /* stream record delimited by LF (sequential org only) */
  401.     X#define         FAB_dol_C_STMCR    6    /* stream record delimited by CR (sequential org only) */
  402.     X#define            FAB_dol_C_MAXRFM    6    /* maximum rfm supported */
  403.     X
  404.     Xchar    recatt;        /* record attributes */
  405.     X
  406.     X#define            FAB_dol_V_FTN    0    /* FORTRAN carriage control character */
  407.     X#define            FAB_dol_V_CR    1    /* line feed - record -carriage return */
  408.     X#define            FAB_dol_V_PRN    2    /* print-file carriage control */
  409.     X#define            FAB_dol_V_BLK    3    /* records don't cross block boundaries */
  410.     X
  411.     X#define    FANO    20
  412.     X
  413.     X#ifdef    pyr
  414.     Xstatic struct    bsa    *file_table[FANO];
  415.     X#else
  416.     Xstruct    bsa    *file_table[FANO];
  417.     X#endif
  418.     X
  419.     XFILE    *f    = NULL;
  420.     Xint    file_count;
  421.     Xshort    reclen;
  422.     Xshort    fix;
  423.     Xshort    recsize;
  424.     Xint    vfcsize;
  425.     X
  426.     X#ifdef    NEWD
  427.     XFILE    *lf;
  428.     X#endif    NEWD
  429.     X
  430.     Xint    fd;        /* tape file descriptor */
  431.     Xint     cflag, dflag, eflag, sflag, tflag, vflag, wflag, xflag;
  432.     Xint    setnr;
  433.     Xchar    **gargv;
  434.     Xint     goptind, gargc;
  435.     X
  436.     X#define    LABEL_SIZE    80
  437.     Xchar    label[LABEL_SIZE];
  438.     X
  439.     Xchar    *block;
  440.     Xint    blocksize;
  441.     X
  442.     Xstruct    mtop    op;
  443.     X
  444.     XFILE *
  445.     Xopenfile(fn)
  446.     Xchar    *fn;
  447.     X{
  448.     X    char    ufn[256];
  449.     X    char    ans[80];
  450.     X    char    *p, *q, s, *ext;
  451.     X    int    procf;
  452.     X
  453.     X    procf = 1;
  454.     X    /* copy fn to ufn and convert to lower case */
  455.     X    p = fn;
  456.     X    q = ufn;
  457.     X    while (*p) {
  458.     X        if (isupper(*p))
  459.     X            *q = *p - 'A' + 'a';
  460.     X        else
  461.     X            *q = *p;
  462.     X        p++;
  463.     X        q++;
  464.     X    }
  465.     X    *q = '\0';
  466.     X
  467.     X    /* convert the VMS to UNIX and make the directory path */
  468.     X    p = ufn;
  469.     X    q = ++p;
  470.     X    while (*q) {
  471.     X        if (*q == '.' || *q == ']') {
  472.     X            s = *q;
  473.     X            *q = '\0';
  474.     X            if(procf && dflag) mkdir(p, 0777);
  475.     X            *q = '/';
  476.     X            if (s == ']')
  477.     X                break;
  478.     X        }
  479.     X        *q++;
  480.     X    }
  481.     X    *q++;
  482.     X    if(!dflag) p=q;
  483.     X    /* strip off the version number */
  484.     X    while (*q && *q != ';') {
  485.     X        if( *q == '.') ext = q;
  486.     X        q++;
  487.     X    }
  488.     X    if (cflag) {
  489.     X        *q = ':';
  490.     X    }
  491.     X    else {
  492.     X        *q = '\0';
  493.     X    }
  494.     X    if(!eflag && procf) procf = typecmp(++ext);
  495.     X    if(procf && wflag) {
  496.     X        printf("extract %s [ny]",filename);
  497.     X        fflush(stdout);
  498.     X        gets(ans);
  499.     X        if(*ans != 'y') procf = NULL;
  500.     X    }
  501.     X    if(procf)
  502.     X        /* open the file for writing */
  503.     X        return(fopen(p, "w"));
  504.     X    else
  505.     X        return(NULL);
  506.     X}
  507.     X
  508.     Xtypecmp(str)    /* Compare the filename type in str with our list
  509.     X                   of file type to be ignored.  Return 0 if the
  510.     X                   file is to be ignored, return 1 if the
  511.     X                   file is not in our list and should not be ignored. */
  512.     Xregister char   *str;
  513.     X{
  514.     X        static char *type[] = {
  515.     X                "exe",          /* vms executable image */
  516.     X                "lib",          /* vms object library */
  517.     X                "obj",          /* rsx object file */
  518.     X                "odl",          /* rsx overlay description file */
  519.     X                "olb",          /* rsx object library */
  520.     X                "pmd",          /* rsx post mortem dump */
  521.     X                "stb",          /* rsx symbol table */
  522.     X                "sys",          /* rsx bootable system image */
  523.     X                "tsk",          /* rsx executable image */
  524.     X        "dir",
  525.     X        "upd",
  526.     X        "tlo",
  527.     X        "tlb",
  528.     X                ""              /* null string terminates list */
  529.     X        };
  530.     X        register int    i;
  531.     X
  532.     X        i = -1;
  533.     X        while (*type[++i])
  534.     X                if (strncmp(str, type[i],3) == 0)
  535.     X                        return(0);      /* found a match, file to be ignored */
  536.     X        return(1);                      /* no match found */
  537.     X}
  538.     X
  539.     Xprocess_file(buffer)
  540.     Xchar    *buffer;
  541.     X{
  542.     X    int    i, n;
  543.     X    char    *p, *q;
  544.     X    short    dsize, nblk, lnch;
  545.     X
  546.     X    int    c;
  547.     X    short    *s;
  548.     X
  549.     X    int     procf;
  550.     X
  551.     X    s = (short *) buffer;
  552.     X
  553.     X    /* check the header word */
  554.     X    if (*s != 257) {
  555.     X        printf("Snark: invalid data header\n");
  556.     X        exit(1);
  557.     X    }
  558.     X
  559.     X    c = 2;
  560.     X    for (i = 0; i < FANO; i++) {
  561.     X        file_table[i] = (struct bsa *) &buffer[c];
  562.     X#ifndef    SWAP
  563.     X        dsize = file_table[i]->bsa_dol_w_size;
  564.     X#else
  565.     X        swap(&file_table[i]->bsa_dol_w_size, &dsize, sizeof(short));
  566.     X#endif
  567.     X        c += dsize + 4;
  568.     X    }
  569.     X
  570.     X    /* extract file name */
  571.     X#ifndef    SWAP
  572.     X    dsize = file_table[0]->bsa_dol_w_size;
  573.     X#else
  574.     X    swap(&file_table[0]->bsa_dol_w_size, &dsize, sizeof(short));
  575.     X#endif
  576.     X    p = file_table[0]->bsa_dol_t_text;
  577.     X    q = filename;
  578.     X    for (i = 0; i < dsize; i++)
  579.     X        *q++ = *p++;
  580.     X    *q = '\0';
  581.     X
  582.     X    /* extract file's record attributes */
  583.     X#ifndef    SWAP
  584.     X    dsize = file_table[5]->bsa_dol_w_size;
  585.     X#else
  586.     X    swap(&file_table[5]->bsa_dol_w_size, &dsize, sizeof(short));
  587.     X#endif
  588.     X    p = file_table[5]->bsa_dol_t_text;
  589.     X    recfmt = p[0];
  590.     X    recatt = p[1];
  591.     X#ifndef    SWAP
  592.     X    bcopy(&p[2], &recsize, sizeof(short));
  593.     X#else
  594.     X    swap(&p[2], &recsize, sizeof(short));
  595.     X#endif
  596.     X    vfcsize = p[15];
  597.     X    if (vfcsize == 0)
  598.     X        vfcsize = 2;
  599.     X#ifdef    DEBUG
  600.     X    printf("recfmt = %d\n", recfmt);
  601.     X    printf("recatt = %d\n", recatt);
  602.     X    printf("reclen = %d\n", recsize);
  603.     X    printf("vfcsize = %d\n", vfcsize);
  604.     X#endif
  605.     X#ifndef    SWAP
  606.     X    bcopy(&p[10], &nblk, sizeof(short));
  607.     X    bcopy(&p[12], &lnch, sizeof(short));
  608.     X#else
  609.     X    swap(&p[10], &nblk, sizeof(short));
  610.     X    swap(&p[12], &lnch, sizeof(short));
  611.     X#endif
  612.     X    filesize = (nblk-1)*512 + lnch;
  613.     X#ifdef DEBUG
  614.     X    printf("nbk = %d, lnch = %d\n", nblk, lnch);
  615.     X    printf("filesize = 0x%x\n", filesize);
  616.     X#endif
  617.     X
  618.     X    /* open the file */
  619.     X    if (f != NULL) {
  620.     X        fclose(f);
  621.     X        file_count = 0;
  622.     X        reclen = 0;
  623.     X    }
  624.     X    procf = 0;
  625.     X    if (goptind < gargc) 
  626.     X        for(i=goptind; i < gargc; i++) {
  627.     X            procf |= match(filename,gargv[i]);
  628.     X        }
  629.     X    else
  630.     X        procf = 1;
  631.     X    if (tflag && procf) 
  632.     X        printf( " %-35s %8d \n",filename,filesize);
  633.     X    if (xflag && procf) {
  634.     X        /* open file */
  635.     X        f = openfile(filename);
  636.     X        if(f != NULL && vflag) printf("extracting %s\n", filename);
  637.     X    }
  638.     X}
  639.     X/*
  640.     X *
  641.     X *  process a virtual block record (file record)
  642.     X *
  643.     X */
  644.     Xprocess_vbn(buffer, rsize)
  645.     Xchar        *buffer;
  646.     Xunsigned short    rsize;
  647.     X{
  648.     X    int    c, i;
  649.     X
  650.     X    if (f == NULL) {
  651.     X        return;
  652.     X    }
  653.     X    i = 0;
  654.     X    while (file_count+i < filesize && i < rsize) {
  655.     X        switch (recfmt) {
  656.     X        case FAB_dol_C_FIX:
  657.     X            if (reclen == 0) {
  658.     X                reclen = recsize;
  659.     X            }
  660.     X            fputc(buffer[i], f);
  661.     X            i++;
  662.     X            reclen--;
  663.     X            break;
  664.     X
  665.     X        case FAB_dol_C_VAR:
  666.     X        case FAB_dol_C_VFC:
  667.     X            if (reclen == 0) {
  668.     X                reclen = *((short *) &buffer[i]);
  669.     X#ifdef    SWAP
  670.     X                swap(&reclen, &reclen, sizeof(short));
  671.     X#endif
  672.     X#ifdef    NEWD
  673.     X                fprintf(lf, "---\n");
  674.     X                fprintf(lf, "reclen = %d\n", reclen);
  675.     X                fprintf(lf, "i = %d\n", i);
  676.     X                fprintf(lf, "rsize = %d\n", rsize);
  677.     X#endif    NEWD
  678.     X                fix = reclen;
  679.     X                i += 2;
  680.     X                if (recfmt == FAB_dol_C_VFC) {
  681.     X                    i += vfcsize;
  682.     X                    reclen -= vfcsize;
  683.     X                }
  684.     X            } else if (reclen == fix
  685.     X                    && recatt == (1 << FAB_dol_V_FTN)) {
  686.     X                    /****
  687.     X                    if (buffer[i] == '0')
  688.     X                        fputc('\n', f);
  689.     X                    else if (buffer[i] == '1')
  690.     X                        fputc('\f', f);
  691.     X                    *** sow ***/
  692.     X                    fputc(buffer[i],f); /** sow **/
  693.     X                    i++;
  694.     X                    reclen--;
  695.     X            } else {
  696.     X                fputc(buffer[i], f);
  697.     X                i++;
  698.     X                reclen--;
  699.     X            }
  700.     X            if (reclen == 0) {
  701.     X                fputc('\n', f);
  702.     X                if (i & 1)
  703.     X                    i++;
  704.     X            }
  705.     X            break;
  706.     X
  707.     X        case FAB_dol_C_STM:
  708.     X        case FAB_dol_C_STMLF:
  709.     X            if (reclen < 0) {
  710.     X                printf("SCREAM\n");
  711.     X            }
  712.     X            if (reclen == 0) {
  713.     X                reclen = 512;
  714.     X            }
  715.     X            c = buffer[i++];
  716.     X            reclen--;
  717.     X            if (c == '\n') {
  718.     X                reclen = 0;
  719.     X            }
  720.     X            fputc(c, f);
  721.     X            break;
  722.     X
  723.     X        case FAB_dol_C_STMCR:
  724.     X            c = buffer[i++];
  725.     X            if (c == '\r')
  726.     X                fputc('\n', f);
  727.     X            else
  728.     X                fputc(c, f);
  729.     X            break;
  730.     X
  731.     X        default:
  732.     X            fclose(f);
  733.     X            unlink(filename);
  734.     X            fprintf(stderr, "Invalid record format = %d\n", recfmt);
  735.     X            return;
  736.     X        }
  737.     X    }
  738.     X    file_count += i;
  739.     X}
  740.     X#ifdef    SWAP
  741.     X/*
  742.     X *
  743.     X *  do swapping for Motorola type architectures
  744.     X *
  745.     X */
  746.     Xswap(from, to, nbytes)
  747.     Xchar    *from, *to;
  748.     Xint    nbytes;
  749.     X{
  750.     X    int    i, j;
  751.     X    char    temp[100];
  752.     X
  753.     X    for (i = 0; i < nbytes; i++)
  754.     X        temp[i] = from[i];
  755.     X    for (i = 0, j = nbytes-1; i < nbytes; i++, j--)
  756.     X        to[i] = temp[j];
  757.     X}
  758.     X#endif
  759.     X/*
  760.     X *
  761.     X *  process a backup block
  762.     X *
  763.     X */
  764.     Xprocess_block(block, blocksize)
  765.     Xchar    *block;
  766.     Xint    blocksize;
  767.     X{
  768.     X
  769.     X    unsigned short    bhsize, rsize, rtype;
  770.     X    unsigned long    bsize, i;
  771.     X
  772.     X    i = 0;
  773.     X
  774.     X    /* read the backup block header */
  775.     X    block_header = (struct bbh *) &block[i];
  776.     X    i += sizeof(struct bbh);
  777.     X
  778.     X    bhsize = block_header->bbh_dol_w_size;
  779.     X    bsize = block_header->bbh_dol_l_blocksize;
  780.     X#ifdef    SWAP
  781.     X    swap(&bhsize, &bhsize, sizeof(short));
  782.     X    swap(&bsize, &bsize, sizeof(long));
  783.     X#endif
  784.     X
  785.     X    /* check the validity of the header block */
  786.     X    if (bhsize != sizeof(struct bbh)) {
  787.     X        fprintf(stderr, "Snark: Invalid header block size\n");
  788.     X        exit(1);
  789.     X    }
  790.     X    if (bsize != 0 && bsize != blocksize) {
  791.     X        fprintf(stderr, "Snark: Invalid block size\n");
  792.     X        exit(1);
  793.     X    }
  794.     X#ifdef    DEBUG
  795.     X    printf("new block: i = %d, bsize = %d\n", i, bsize);
  796.     X#endif
  797.     X
  798.     X    /* read the records */
  799.     X    while (i < bsize) {
  800.     X        /* read the backup record header */
  801.     X        record_header = (struct brh *) &block[i];
  802.     X        i += sizeof(struct brh);
  803.     X
  804.     X        rtype = record_header->brh_dol_w_rtype;
  805.     X        rsize = record_header->brh_dol_w_rsize;
  806.     X#ifdef    SWAP
  807.     X        swap(&rtype, &rtype, sizeof(short));
  808.     X        swap(&rsize, &rsize, sizeof(short));
  809.     X#endif
  810.     X#ifdef    DEBUG
  811.     X        printf("rtype = %d\n", rtype);
  812.     X        printf("rsize = %d\n", rsize);
  813.     X        printf("flags = 0x%x\n", record_header->brh_dol_l_flags);
  814.     X        printf("addr = 0x%x\n", record_header->brh_dol_l_address);
  815.     X        printf("i = %d\n", i);
  816.     X#endif
  817.     X
  818.     X        switch (rtype) {
  819.     X
  820.     X        case brh_dol_k_null:
  821.     X#ifdef    DEBUG
  822.     X            printf("rtype = null\n");
  823.     X#endif
  824.     X            break;
  825.     X
  826.     X        case brh_dol_k_summary:
  827.     X#ifdef    DEBUG
  828.     X            printf("rtype = summary\n");
  829.     X#endif
  830.     X            break;
  831.     X
  832.     X        case brh_dol_k_file:
  833.     X#ifdef    DEBUG
  834.     X            printf("rtype = file\n");
  835.     X#endif
  836.     X            process_file(&block[i]);
  837.     X            break;
  838.     X
  839.     X        case brh_dol_k_vbn:
  840.     X#ifdef    DEBUG
  841.     X            printf("rtype = vbn\n");
  842.     X#endif
  843.     X            process_vbn(&block[i], rsize);
  844.     X            break;
  845.     X
  846.     X        case brh_dol_k_physvol:
  847.     X#ifdef    DEBUG
  848.     X            printf("rtype = physvol\n");
  849.     X#endif
  850.     X            break;
  851.     X
  852.     X        case brh_dol_k_lbn:
  853.     X#ifdef    DEBUG
  854.     X            printf("rtype = lbn\n");
  855.     X#endif
  856.     X            break;
  857.     X
  858.     X        case brh_dol_k_fid:
  859.     X#ifdef    DEBUG
  860.     X            printf("rtype = fid\n");
  861.     X#endif
  862.     X            break;
  863.     X
  864.     X        default:
  865.     X            fprintf(stderr, " Snark: invalid record type\n");
  866.     X            fprintf(stderr, " record type = %d\n", rtype);
  867.     X            exit(1);
  868.     X        }
  869.     X#ifdef pyr
  870.     X        i = i + rsize;
  871.     X#else
  872.     X        i += rsize;
  873.     X#endif
  874.     X    }
  875.     X}
  876.     X
  877.     Xrdhead()
  878.     X{
  879.     X    int i, nfound;
  880.     X    char name[80];
  881.     X    nfound = 1;
  882.     X    /* read the tape label - 4 records of 80 bytes */
  883.     X    while ((i = read(fd, label, LABEL_SIZE)) != 0) {
  884.     X        if (i != LABEL_SIZE) {
  885.     X            fprintf(stderr, "Snark: bad label record\n");
  886.     X            exit(1);
  887.     X        }
  888.     X        if (strncmp(label, "VOL1",4) == 0) {
  889.     X            sscanf(label+4, "%14s", name);
  890.     X            if(vflag || tflag) printf("Volume: %s\n",name);
  891.     X        }
  892.     X        if (strncmp(label, "HDR1",4) == 0) {
  893.     X            sscanf(label+4, "%14s", name);
  894.     X            sscanf(label+31, "%4d", &setnr);
  895.     X        }
  896.     X        /* get the block size */
  897.     X        if (strncmp(label, "HDR2", 4) == 0) {
  898.     X            nfound = 0;
  899.     X            sscanf(label+5, "%5d", &blocksize);
  900.     X#ifdef    DEBUG
  901.     X            printf("blocksize = %d\n", blocksize);
  902.     X#endif
  903.     X        }
  904.     X    }
  905.     X    if((vflag || tflag) && !nfound) 
  906.     X        printf("Saveset name: %s   number: %d\n",name,setnr);
  907.     X    /* get the block buffer */
  908.     X    block = (char *) malloc(blocksize);
  909.     X    if (block == (char *) 0) {
  910.     X        fprintf(stderr, "memory allocation for block failed\n");
  911.     X        exit(1);
  912.     X    }
  913.     X    return(nfound);
  914.     X}
  915.     X
  916.     Xrdtail()
  917.     X{
  918.     X    int i;
  919.     X    char name[80];
  920.     X    /* read the tape label - 4 records of 80 bytes */
  921.     X    while ((i = read(fd, label, LABEL_SIZE)) != 0) {
  922.     X        if (i != LABEL_SIZE) {
  923.     X            fprintf(stderr, "Snark: bad label record\n");
  924.     X            exit(1);
  925.     X        }
  926.     X        if (strncmp(label, "EOF1",4) == 0) {
  927.     X            sscanf(label+4, "%14s", name);
  928.     X            if(vflag || tflag)
  929.     X                printf("End of saveset: %s\n\n\n",name);
  930.     X        }
  931.     X    }
  932.     X}
  933.     X
  934.     Xusage(progname)
  935.     Xchar    *progname;
  936.     X{
  937.     X    fprintf(stderr,
  938.     X      "Usage:  %s -{tx}[cdevw][-s setnumber][-f tapefile]\n",progname);
  939.     X}
  940.     Xmain(argc, argv)
  941.     Xint    argc;
  942.     Xchar    *argv[];
  943.     X{
  944.     X    
  945.     X    char *progname;
  946.     X    int    c, i, eoffl;
  947.     X    int    selset;
  948.     X    extern int optind;
  949.     X    extern char *optarg;
  950.     X
  951.     X    progname = argv[0];
  952.     X    if(argc < 2){
  953.     X        usage(progname);
  954.     X        exit(1);
  955.     X    }
  956.     X    gargv = argv;
  957.     X    gargc = argc;
  958.     X    tapefile = def_tapefile;
  959.     X    cflag=dflag=eflag=sflag=tflag=vflag=wflag=xflag=0;
  960.     X    while((c=getopt(argc,argv,"cdef:s:tvwx")) != EOF)
  961.     X        switch(c){
  962.     X        case 'c':
  963.     X            cflag++;
  964.     X            break;
  965.     X        case 'd':
  966.     X            dflag++;
  967.     X            break;
  968.     X        case 'e':
  969.     X            eflag++;
  970.     X            break;
  971.     X        case 'f':
  972.     X            tapefile = optarg;
  973.     X            break;
  974.     X        case 's':
  975.     X            sflag++;
  976.     X            sscanf(optarg,"%d",&selset);
  977.     X            break;
  978.     X        case 't':
  979.     X            tflag++;
  980.     X            break;
  981.     X        case 'v':
  982.     X            vflag++;
  983.     X            break;
  984.     X        case 'w':
  985.     X            wflag++;
  986.     X            break;
  987.     X        case 'x':
  988.     X            xflag++;
  989.     X            break;
  990.     X        case '?':
  991.     X            usage(progname);
  992.     X            exit(1);
  993.     X            break;
  994.     X        };
  995.     X    if(!tflag && !xflag) {
  996.     X        usage(progname);
  997.     X        exit(1);
  998.     X    }
  999.     X    goptind = optind;
  1000.     X
  1001.     X#ifdef    NEWD
  1002.     X    /* open debug file */
  1003.     X    lf = fopen("log", "w");
  1004.     X    if (lf == NULL) {
  1005.     X        perror("log");
  1006.     X        exit(1);
  1007.     X    }
  1008.     X#endif
  1009.     X
  1010.     X    /* open the tape file */
  1011.     X    fd = open(tapefile, O_RDONLY);
  1012.     X    if (fd < 0) {
  1013.     X        perror(tapefile);
  1014.     X        exit(1);
  1015.     X    }
  1016.     X
  1017.     X    /* rewind the tape */
  1018.     X    op.mt_op = MTREW;
  1019.     X    op.mt_count = 1;
  1020.     X    i = ioctl(fd, MTIOCTOP, &op);
  1021.     X    if (i < 0) {
  1022.     X        perror(tapefile);
  1023.     X        exit(1);
  1024.     X    }
  1025.     X
  1026.     X    eoffl = rdhead();
  1027.     X    /* read the backup tape blocks until end of tape */ 
  1028.     X    while (!eoffl) {
  1029.     X        if(sflag && setnr != selset) {
  1030.     X            op.mt_op = MTFSF;
  1031.     X            op.mt_count = 1;
  1032.     X            i = ioctl(fd, MTIOCTOP, &op);
  1033.     X            if (i < 0) {
  1034.     X                perror(tapefile);
  1035.     X                exit(1);
  1036.     X            }
  1037.     X            i = 0;
  1038.     X        }
  1039.     X        else
  1040.     X            i = read(fd, block, blocksize);
  1041.     X        if(i == 0) {
  1042.     X            rdtail();
  1043.     X            eoffl=rdhead();
  1044.     X        }
  1045.     X        else if (i != blocksize) {
  1046.     X            fprintf(stderr, "bad block read i = %d\n", i);
  1047.     X            exit(1);
  1048.     X        }
  1049.     X        else{
  1050.     X            eoffl = 0;
  1051.     X            process_block(block, blocksize);
  1052.     X        }
  1053.     X    }
  1054.     X    if(vflag || tflag) printf("End of tape\n");
  1055.     X
  1056.     X    /* close the tape */
  1057.     X    close(fd);
  1058.     X
  1059.     X#ifdef    NEWD
  1060.     X    /* close debug file */
  1061.     X    fclose(lf);
  1062.     X#endif    NEWD
  1063.     X
  1064.     X    /* exit cleanly */
  1065.     X    exit(0);
  1066.     X}
  1067. SHAR_EOF
  1068. if test 16594 -ne "`wc -c < 'vmsbackup.c'`"
  1069. then
  1070.     echo shar: "error transmitting 'vmsbackup.c'" '(should have been 16594 characters)'
  1071. fi
  1072. fi
  1073. echo shar: "extracting 'match.c'" '(6723 characters)'
  1074. if test -f 'match.c'
  1075. then
  1076.     echo shar: "will not over-write existing file 'match.c'"
  1077. else
  1078. sed 's/^    X//' << \SHAR_EOF > 'match.c'
  1079.     X#include <stdio.h>
  1080.     X#include <sys/types.h>
  1081.     X
  1082.     X#define ASTERISK '*'        /* The '*' metacharacter */
  1083.     X#define QUESTION '?'        /* The '?' metacharacter */
  1084.     X#define LEFT_BRACKET '['    /* The '[' metacharacter */
  1085.     X#define RIGHT_BRACKET ']'    /* The ']' metacharacter */
  1086.     X
  1087.     X#define IS_OCTAL(ch) (ch >= '0' && ch <= '7')
  1088.     X
  1089.     Xtypedef int BOOLEAN;
  1090.     X#define VOID void
  1091.     X#define TRUE 1
  1092.     X#define FALSE 0
  1093.     X#define EOS '\000'
  1094.     X
  1095.     Xstatic BOOLEAN do_list ();
  1096.     Xstatic char nextch ();
  1097.     Xstatic VOID list_parse ();
  1098.     X
  1099.     X
  1100.     X/*
  1101.     X *  FUNCTION
  1102.     X *
  1103.     X *    match    test string for wildcard match
  1104.     X *
  1105.     X *  SYNOPSIS
  1106.     X *
  1107.     X *    BOOLEAN match (string, pattern)
  1108.     X *    register char *string;
  1109.     X *    register char *pattern;
  1110.     X *
  1111.     X *  DESCRIPTION
  1112.     X *
  1113.     X *    Test string for match using pattern.  The pattern may
  1114.     X *    contain the normal shell metacharacters for pattern
  1115.     X *    matching.  The '*' character matches any string,
  1116.     X *    including the null string.  The '?' character matches
  1117.     X *    any single character.  A list of characters enclosed
  1118.     X *    in '[' and ']' matches any character in the list.
  1119.     X *    If the first character following the beginning '['
  1120.     X *    is a '!' then any character not in the list is matched.
  1121.     X *
  1122.     X */
  1123.     X
  1124.     X
  1125.     X/*
  1126.     X *  PSEUDO CODE
  1127.     X *
  1128.     X *    Begin match
  1129.     X *        Switch on type of pattern character
  1130.     X *        Case ASTERISK:
  1131.     X *            Attempt to match asterisk
  1132.     X *            Break
  1133.     X *        Case QUESTION MARK:
  1134.     X *            Attempt to match question mark
  1135.     X *            Break
  1136.     X *        Case EOS:
  1137.     X *            Match is result of EOS on string test
  1138.     X *            Break
  1139.     X *        Case default:
  1140.     X *            If explicit match then
  1141.     X *            Match is result of submatch
  1142.     X *            Else
  1143.     X *            Match is FALSE
  1144.     X *            End if
  1145.     X *            Break
  1146.     X *        End switch
  1147.     X *        Return result of match test
  1148.     X *    End match
  1149.     X *
  1150.     X */
  1151.     X
  1152.     XBOOLEAN match (string, pattern)
  1153.     Xregister char *string;
  1154.     Xregister char *pattern;
  1155.     X{
  1156.     X    register BOOLEAN ismatch;
  1157.     X
  1158.     X    ismatch = FALSE;
  1159.     X    switch (*pattern) {
  1160.     X    case ASTERISK:
  1161.     X        pattern++;
  1162.     X        do {
  1163.     X        ismatch = match (string, pattern);
  1164.     X        } while (!ismatch && *string++ != EOS);
  1165.     X        break;
  1166.     X    case QUESTION:
  1167.     X        if (*string != EOS) {
  1168.     X        ismatch = match (++string, ++pattern);
  1169.     X        }
  1170.     X        break;
  1171.     X    case EOS:
  1172.     X        if (*string == EOS) {
  1173.     X        ismatch = TRUE;
  1174.     X        }
  1175.     X        break;
  1176.     X    case LEFT_BRACKET:
  1177.     X        if (*string != EOS) {
  1178.     X        ismatch = do_list (string, pattern);
  1179.     X        }
  1180.     X        break;
  1181.     X    default:
  1182.     X        if (*string++ == *pattern++) {
  1183.     X        ismatch = match (string, pattern);
  1184.     X        } else {
  1185.     X        ismatch = FALSE;
  1186.     X        }
  1187.     X        break;
  1188.     X    }
  1189.     X    return (ismatch);
  1190.     X}
  1191.     X
  1192.     X
  1193.     X/*
  1194.     X *  FUNCTION
  1195.     X *
  1196.     X *    do_list    process a list and following substring
  1197.     X *
  1198.     X *  SYNOPSIS
  1199.     X *
  1200.     X *    static BOOLEAN do_list (string, pattern)
  1201.     X *    register char *string;
  1202.     X *    register char *pattern;
  1203.     X *
  1204.     X *  DESCRIPTION
  1205.     X *
  1206.     X *    Called when a list is found in the pattern.  Returns
  1207.     X *    TRUE if the current character matches the list and
  1208.     X *    the remaining substring matches the remaining pattern.
  1209.     X *
  1210.     X *    Returns FALSE if either the current character fails to
  1211.     X *    match the list or the list matches but the remaining
  1212.     X *    substring and subpattern's don't.
  1213.     X *
  1214.     X *  RESTRICTIONS
  1215.     X *
  1216.     X *    The mechanism used to match characters in an inclusive
  1217.     X *    pair (I.E. [a-d]) may not be portable to machines
  1218.     X *    in which the native character set is not ASCII.
  1219.     X *
  1220.     X *    The rules implemented here are:
  1221.     X *
  1222.     X *        (1)    The backslash character may be
  1223.     X *            used to quote any special character.
  1224.     X *            I.E.  "\]" and "\-" anywhere in list,
  1225.     X *            or "\!" at start of list.
  1226.     X *
  1227.     X *        (2)    The sequence \nnn becomes the character
  1228.     X *            given by nnn (in octal).
  1229.     X *
  1230.     X *        (3)    Any non-escaped ']' marks the end of list.
  1231.     X *
  1232.     X *        (4)    A list beginning with the special character
  1233.     X *            '!' matches any character NOT in list.
  1234.     X *            The '!' character is only special if it
  1235.     X *            is the first character in the list.
  1236.     X *
  1237.     X */
  1238.     X
  1239.     X
  1240.     X/*
  1241.     X *  PSEUDO CODE
  1242.     X *
  1243.     X *    Begin do_list
  1244.     X *        Default result is no match
  1245.     X *        Skip over the opening left bracket
  1246.     X *        If the next pattern character is a '!' then
  1247.     X *        List match gives FALSE
  1248.     X *        Skip over the '!' character
  1249.     X *        Else
  1250.     X *        List match gives TRUE
  1251.     X *        End if
  1252.     X *        While not at closing bracket or EOS
  1253.     X *        Get lower and upper bounds
  1254.     X *        If character in bounds then
  1255.     X *            Result is same as sense flag.
  1256.     X *            Skip over rest of list
  1257.     X *        End if
  1258.     X *        End while
  1259.     X *        If match found then
  1260.     X *        If not at end of pattern then
  1261.     X *            Call match with rest of pattern
  1262.     X *        End if
  1263.     X *        End if
  1264.     X *        Return match result
  1265.     X *    End do_list
  1266.     X *
  1267.     X */
  1268.     X
  1269.     Xstatic BOOLEAN do_list (string, pattern)
  1270.     Xregister char *string;
  1271.     Xchar *pattern;
  1272.     X{
  1273.     X    register BOOLEAN ismatch;
  1274.     X    register BOOLEAN if_found;
  1275.     X    register BOOLEAN if_not_found;
  1276.     X    auto char lower;
  1277.     X    auto char upper;
  1278.     X
  1279.     X    pattern++;
  1280.     X    if (*pattern == '!') {
  1281.     X    if_found = FALSE;
  1282.     X    if_not_found = TRUE;
  1283.     X    pattern++;
  1284.     X    } else {
  1285.     X    if_found = TRUE;
  1286.     X    if_not_found = FALSE;
  1287.     X    }
  1288.     X    ismatch = if_not_found;
  1289.     X    while (*pattern != ']' && *pattern != EOS) {
  1290.     X    list_parse (&pattern, &lower, &upper);
  1291.     X    if (*string >= lower && *string <= upper) {
  1292.     X        ismatch = if_found;
  1293.     X        while (*pattern != ']' && *pattern != EOS) {pattern++;}
  1294.     X    }
  1295.     X    }
  1296.     X    if (*pattern++ != ']') {
  1297.     X    fprintf (stderr, "warning - character class error\n");
  1298.     X    } else {
  1299.     X    if (ismatch) {
  1300.     X        ismatch = match (++string, pattern);
  1301.     X    }
  1302.     X    }
  1303.     X    return (ismatch);
  1304.     X}
  1305.     X
  1306.     X
  1307.     X/*
  1308.     X *  FUNCTION
  1309.     X *
  1310.     X *    list_parse    parse part of list into lower and upper bounds
  1311.     X *
  1312.     X *  SYNOPSIS
  1313.     X *
  1314.     X *    static VOID list_parse (patp, lowp, highp)
  1315.     X *    char **patp;
  1316.     X *    char *lowp;
  1317.     X *    char *highp;
  1318.     X *
  1319.     X *  DESCRIPTION
  1320.     X *
  1321.     X *    Given pointer to a pattern pointer (patp), pointer to
  1322.     X *    a place to store lower bound (lowp), and pointer to a
  1323.     X *    place to store upper bound (highp), parses part of
  1324.     X *    the list, updating the pattern pointer in the process.
  1325.     X *
  1326.     X *    For list characters which are not part of a range,
  1327.     X *    the lower and upper bounds are set to that character.
  1328.     X *
  1329.     X */
  1330.     X
  1331.     Xstatic VOID list_parse (patp, lowp, highp)
  1332.     Xchar **patp;
  1333.     Xchar *lowp;
  1334.     Xchar *highp;
  1335.     X{
  1336.     X    *lowp = nextch (patp);
  1337.     X    if (**patp == '-') {
  1338.     X    (*patp)++;
  1339.     X    *highp = nextch (patp);
  1340.     X    } else {
  1341.     X    *highp = *lowp;
  1342.     X    }
  1343.     X}
  1344.     X
  1345.     X
  1346.     X/*
  1347.     X *  FUNCTION
  1348.     X *
  1349.     X *    nextch      determine next character in a pattern
  1350.     X *
  1351.     X *  SYNOPSIS
  1352.     X *
  1353.     X *    static char nextch (patp)
  1354.     X *    char **patp;
  1355.     X *
  1356.     X *  DESCRIPTION
  1357.     X *
  1358.     X *    Given pointer to a pointer to a pattern, uses the pattern
  1359.     X *    pointer to determine the next character in the pattern,
  1360.     X *    subject to translation of backslash-char and backslash-octal
  1361.     X *    sequences.
  1362.     X *
  1363.     X *    The character pointer is updated to point at the next pattern
  1364.     X *    character to be processed.
  1365.     X *
  1366.     X */
  1367.     X
  1368.     Xstatic char nextch (patp)
  1369.     Xchar **patp;
  1370.     X{
  1371.     X    register char ch;
  1372.     X    register char chsum;
  1373.     X    register int count;
  1374.     X
  1375.     X    ch = *(*patp)++;
  1376.     X    if (ch == '\\') {
  1377.     X    ch = *(*patp)++;
  1378.     X    if (IS_OCTAL (ch)) {
  1379.     X        chsum = 0;
  1380.     X        for (count = 0; count < 3 && IS_OCTAL (ch); count++) {
  1381.     X        chsum *= 8;
  1382.     X        chsum += ch - '0';
  1383.     X        ch = *(*patp)++;
  1384.     X        }
  1385.     X        (*patp)--;
  1386.     X        ch = chsum;
  1387.     X    }
  1388.     X    }
  1389.     X    return (ch);
  1390.     X}
  1391. SHAR_EOF
  1392. if test 6723 -ne "`wc -c < 'match.c'`"
  1393. then
  1394.     echo shar: "error transmitting 'match.c'" '(should have been 6723 characters)'
  1395. fi
  1396. fi
  1397. exit 0
  1398. #    End of shell archive
  1399.  
  1400.